#include"data.hpp"
#include"config.hpp"
#include"util.hpp"
#include"httplib.h"
extern cloud::DataManager* data;
namespace cloud
{
    class Service
    {
        private:
            std::string _ip;
            int  _port;
            std::string _download_prefix;
            httplib::Server _serivce;
            static std::string TimetoStr(time_t time)
            {
                std::string tmp = std::ctime(&time);
                return tmp;
            }
            static void ListShow(const httplib::Request& req,httplib::Response& res)
            {
                std::vector<BackupInfo> vb;
                data->GetAll(&vb);
                std::stringstream ss;
                ss<<R"(<!doctype html><html><head><meta charset="UTF-8"><title>Download</title></head><body><h1>Download</h1><table>)";
                for(int i = 0;i < vb.size();i++)
                {//R"()"
                    ss<<R"(<tr>)";
                    ss<<R"(<td><a href=")" <<vb[i].url<<R"(">)"<<Util::FileUtil(vb[i].real_path).FileName()<<R"(</a></td>)";
                    ss<<R"(<td>)"<< TimetoStr(vb[i].atime)<<R"(</td>)";
                    ss<<R"(<td>)"<< vb[i].fsize/1024 <<R"(k</td>)";
                    ss<<R"(</tr>)";
                }
                ss<<R"(</table></body></html>)";
                res.body = ss.str();
                res.status = 200;
                res.set_header("Content-Type","text/html");
                return;
                
            }
            static void UpLoad(const httplib::Request& req,httplib::Response& res)
            {
                auto ret = req.has_file("file");
                if(ret == false)
                {
                    res.status = 400;
                    return;
                }
                res.status = 200;

                Config* conf = Config::GetInstance();

                const auto& file = req.get_file_value("file");

                std::string realpath = conf->GetBackDir()+Util::FileUtil(file.filename).FileName();
                Util::FileUtil backfile(realpath);
                backfile.SetContent(file.content);

                BackupInfo backfile_info(realpath);
                data->Insert(backfile_info);
                return;

            }
            static std::string GetETag(const BackupInfo& info)
            {
                std::string etag;
                etag+=info.pack_path;
                etag+="-";
                etag+=std::to_string(info.fsize);
                etag+="-";
                etag+=std::to_string(info.mtime);
                return etag;
            }
            static void DownLoad(const httplib::Request& req,httplib::Response& res)
            {
                BackupInfo info;
                data->GetOneByURL(req.path,&info);
                if(info.pack_flag == true)
                {
                    Util::FileUtil file(info.pack_path);
                    file.UnCompress(info.real_path);
                    file.Remove();
                    info.pack_flag = false;
                    data->Update(info);
                }

                
                Util::FileUtil file(info.real_path);
                file.GetContent(&res.body);

                std::string old_etag;
                bool retrans = false;
                if(req.has_header("If-Range") == true)
                {
                    old_etag = req.get_header_value("If-Range");
                    if(old_etag == GetETag(info))
                    {
                        retrans = true;
                    }
                }
                if(retrans == false)
                {
                    res.set_header("Accept-Ranges","bytes");
                    res.set_header("ETag",GetETag(info));
                    res.set_header("Content-Type","application/octet-stream");
                    res.status = 200;                    
                }
                else
                {
                    res.set_header("Accept-Ranges","bytes");
                    res.set_header("ETag",GetETag(info));
                    res.set_header("Content-Type","application/octet-stream");
                    res.status = 206;  
                }


            }

        public:
            Service()
            {
                Config* conf = Config::GetInstance();
                _ip = conf->GetServerIp();
                _port = conf->GetServerPort();
                _download_prefix = conf->GetDownloadPrefix();
            }
            bool RunModule()
            {
                _serivce.Post("/upload",UpLoad);
                _serivce.Get("/listshow",ListShow);
                _serivce.Get("/",ListShow);
                std::string download_utl = _download_prefix+"(.*)";
                _serivce.Get(download_utl,DownLoad);
                _serivce.listen(_ip,_port);
                return true;
            }
    };
}
